package com.slowfly.rule.engine.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.slowfly.rule.engine.entity.Scene;
import com.slowfly.rule.engine.entity.Strategy;
import com.slowfly.rule.engine.entity.StrategyRecord;
import com.slowfly.rule.engine.mapper.StrategyRecordMapper;
import com.slowfly.rule.engine.param.StrategyRecordParam;
import com.slowfly.rule.engine.result.ExecuteRiskResult;
import com.slowfly.rule.engine.result.PageResult;
import com.slowfly.rule.engine.result.StrategyRecordResult;
import com.slowfly.rule.engine.service.ISceneService;
import com.slowfly.rule.engine.service.IStrategyFuseService;
import com.slowfly.rule.engine.service.IStrategyRecordService;
import com.slowfly.rule.engine.util.JsonUtils;
import com.slowfly.rule.engine.util.PageResultConvert;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author shalongfei
 * @since 2024-03-04
 */
@Slf4j
@Service
public class StrategyRecordServiceImpl extends ServiceImpl<StrategyRecordMapper, StrategyRecord> implements IStrategyRecordService {

    private static final ExecutorService executorService = Executors.newFixedThreadPool(16);

    @Autowired
    private ISceneService sceneService;
    @Autowired
    private IStrategyFuseService strategyFuseService;

    public void save(long riskId, Strategy strategy, String scripts, Map<String, Object> featureValues, Integer decisionId,
                     boolean execute, ExecuteRiskResult result) {
        Scene scene = sceneService.get(strategy.getSceneId());
        StrategyRecord strategyRecord = new StrategyRecord();
        strategyRecord.setSceneId(strategy.getSceneId());
        if (Objects.nonNull(scene)) {
            strategyRecord.setSceneName(scene.getName());
        }
        strategyRecord.setStrategyId(strategy.getId());
        strategyRecord.setStrategyName(strategy.getName());
        strategyRecord.setStrategyPriority(strategy.getPriority());
        strategyRecord.setStrategyStatus(strategy.getStatus());
        strategyRecord.setRiskId(riskId);
        strategyRecord.setScripts(scripts);
        strategyRecord.setFeatureValues(JsonUtils.toJson(featureValues));
        strategyRecord.setDecisionId(decisionId);
        strategyRecord.setHit(Objects.nonNull(decisionId));
        strategyRecord.setExecute(execute);
        if (execute) {
            strategyRecord.setResultType(result.getResultType());
            strategyRecord.setResultMsg(result.getResultMsg());
            strategyRecord.setTemplateId(result.getTemplateId());
            strategyRecord.setNoticeUsers(JsonUtils.toJson(result.getNoticeUsers()));
            strategyRecord.setNoticeMsg(result.getNoticeMsg());
        }
        CompletableFuture.runAsync(() -> {
            // 保存策略日志
            save(strategyRecord);
            // 策略熔断
            strategyFuseService.riskStrategyFuse(strategy.getFuse(), strategyRecord);
        }, executorService);
    }

    public PageResult<StrategyRecordResult> pageStrategyRecord(StrategyRecordParam param) {
        LambdaQueryWrapper<StrategyRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Objects.nonNull(param.getRiskId()), StrategyRecord::getRiskId, param.getRiskId());
        queryWrapper.eq(Objects.nonNull(param.getStrategyId()), StrategyRecord::getStrategyId, param.getStrategyId());
        queryWrapper.eq(Objects.nonNull(param.getHit()), StrategyRecord::getHit, param.getHit());
        queryWrapper.eq(Objects.nonNull(param.getExecute()), StrategyRecord::getExecute, param.getExecute());
        queryWrapper.orderByDesc(StrategyRecord::getCreateTime);
        Page<StrategyRecord> page = page(new Page<>(param.getPageNo(), param.getPageSize()), queryWrapper);
        return PageResultConvert.convert(page, StrategyRecordResult.class);
    }
}
